#!/bin/bash
source $LFS/sources/pkg/utils.sh || exit 1;

function pkgsearch {
    PKG_NAMEPATTERN='';
    PKG_VERSIONPATTERN='*';
    ARGP="";
    for a in $@; do
        if [[ $a == "-p" ]]; then
            ARGP='*';
        else
            if [[ $PKG_NAMEPATTERN == '' ]]; then
                PKG_NAMEPATTERN=$a;
            else
                PKG_VERSIONPATTERN=$a;
            fi
        fi
    done
    #errcho "/usr/pkg/${PKG_NAMEPATTERN}${ARGP}_${PKG_VERSIONPATTERN}${ARGP}_pkg.tar.gz";
	PKG_LIST="";
	for pkg in /usr/pkg/${PKG_NAMEPATTERN}${ARGP}_${PKG_VERSIONPATTERN}${ARGP}_pkg.tar.gz; do
		if [ ! -r $pkg ]; then continue; fi
		PKG_ARCHIVE=$(echo $pkg | sed -e 's|/usr/pkg/||') && \
		PKG_ENTRY=$(echo $PKG_ARCHIVE | grep -o -e '^.*_.*_pkg.tar' | sed -e 's|_pkg.tar||') && \
		PKG_NAME=$(echo $PKG_ENTRY | cut -d'_' -f1);
		if (($? != 0)); then
			errcho "pkgsearch: error while searching for $1";
			return 1;
		fi
		#errcho "Found: $PKG_NAME $PKG_ARCHIVE $PKG_ENTRY";
		if [[ $(echo "$PKG_LIST" | grep "^${PKG_NAME}$") != "" ]]; then continue; fi
		PKG_LIST="$(echo "$PKG_LIST"; echo $PKG_NAME)";
	done
	echo "$PKG_LIST" | grep -v '^$' || return 0;
}

function pkginstalled {
	PKG_LIST="";
    PKG_VERSIONPATTERN=$(if [ -z $2 ]; then echo '*'; else echo "$2"; fi);
	for pkg in /usr/pkg/installed.db/${1}_${PKG_VERSIONPATTERN}_pkg.info; do
		if [ ! -r $pkg ]; then continue; fi
		PKG_INFO=$(echo $pkg | sed -e 's|/usr/pkg/installed.db/||') && \
		PKG_ENTRY=$(echo $PKG_INFO | grep -o -e '^.*_.*_pkg.info' | sed -e 's|_pkg.info||') && \
		PKG_NAME=$(echo $PKG_ENTRY | cut -d'_' -f1);
		if (($? != 0)); then
			errcho "pkginstalled: error while searching for installed packages $1";
			return 1;
		fi
		if [[ $(echo "$PKG_LIST" | grep "^${PKG_NAME}$") != "" ]]; then continue; fi
		PKG_LIST="$(echo "$PKG_LIST"; echo $PKG_NAME)";
	done
	echo "$PKG_LIST" | grep -v '^$';
}

function pkgunlocked {
	PKG_LIST="";
    PKG_LOCKED="";
    PKG_VERSIONPATTERN=$(if [ -z $2 ]; then echo '*'; else echo "$2"; fi);
	for lock in /usr/pkg/installed.db/${1}_${PKG_VERSIONPATTERN}_pkg.lock; do
        pkg=$(echo $lock | sed -e 's|_pkg.lock$|_pkg.info|') || return 1;
		if [ ! -r $pkg ]; then continue; fi
		PKG_INFO=$(cat $pkg | grep -v '^#' | grep -v '^$' | head -1 | tr -s [:blank:] ' ') && \
        (($(echo $PKG_INFO | wc -w) >= 3)) && \
		PKG_NAME=$(echo $PKG_INFO | cut -d' ' -f1) && \
		PKG_VERSION=$(echo $PKG_INFO | cut -d' ' -f3);
		if (($? != 0)); then
			errcho "pkgunlocked: error while searching for installed package info $PKG_INFO --> $pkg";
			continue;
		fi
		#errcho "$pkg found... check if active locks exists...";
		PKG_DEPS="$(cat $lock | grep -v '^#' | grep -v '^$')" || return 3;
        #errcho "locked: $PKG_DEPS"
        ACTIVE_LOCKS="";
		IFS=$'\n';
		for d in $PKG_DEPS; do
            DEP_NAME=$(echo $d | cut -d' ' -f1) || return 5;
			INSTVERS="$(pkginstver $DEP_NAME)" || return 6;
            #errcho "installed package $DEP_NAME --> versions: $INSTVERS";
			if (($(echo $d | wc -w) >= 2)); then
				DEP_VER=$(echo $d | cut -d' ' -f2);
				if [[ $(echo "$INSTVERS" | grep "^$DEP_VER") != "" ]]; then
                    ACTIVE_LOCKS=$(echo "$ACTIVE_LOCKS"; echo $d);
				fi
			elif [[ $INSTVERS != "" ]]; then
				ACTIVE_LOCKS=$(echo "$ACTIVE_LOCKS"; echo $DEP_NAME $(echo "$INSTVERS" | grep -v '^$' | head -1));
			fi
		done
        # are there active locks?
        if [[ $ACTIVE_LOCKS == "" && $(echo "$PKG_LOCKED" | grep "^${PKG_NAME}$") == "" ]]; then
            # all active locks gone
            PKG_LIST=$(echo "$PKG_LIST"; echo $PKG_NAME);
        else
            PKG_LOCKED=$(echo "$PKG_LOCKED"; echo "$PKG_NAME");
            PKG_LIST=$(echo "$PKG_LIST" | grep -v "^${PKG_NAME}$");
            errcho "$PKG_NAME $PKG_VERSION has active locks... ignore";
        fi
	done
	echo "$PKG_LIST" | grep -v '^$' || return 0;
}

function pkgversions {
	if [ -z $1 ]; then
        errcho "pkgversions: missing argument 1 (package name)";
        return 1;
    fi
	PKG_NAME=$1;
	PKG_LIST="$(pkgsearch $1)";
	
	if [[ $(echo "$PKG_LIST" | grep "^${PKG_NAME}$") == "" ]]; then
		errcho "pkgversions: couldn't find exactly match of package $1";
		return 2;
	fi
	if (($(echo "$PKG_LIST" | wc -l) != 1)); then
		errcho "pkgversions: couldn't find exactly match of package $1";
		return 3;
	fi
	PKG_MAX="";
	PKG_LIST="";
	for pkg in /usr/pkg/${PKG_NAME}_*_pkg.tar.gz; do
		if [ ! -r $pkg ]; then continue; fi
		PKG_ARCHIVE=$(echo $pkg | sed -e 's|/usr/pkg/||') && \
		PKG_ENTRY=$(echo $PKG_ARCHIVE | grep -o -e '^.*_.*_pkg.tar' | sed -e 's|_pkg.tar||') && \
		PKG_VERSION=$(echo $PKG_ENTRY | cut -d'_' -f2-);
		if (($? != 0)); then
			errcho "pkgversions: error while searching for $1";
			return 4;
		fi
		#errcho "Found: $PKG_ENTRY $PKG_VERSION";
		[ -z $PKG_MAX ] && PKG_MAX=$PKG_VERSION;
		if [[ $(echo "$PKG_LIST" | grep "^${PKG_VERSION}$") != "" ]]; then continue; fi
		# remind the maximum version
		versionmatch $PKG_MAX $PKG_VERSION 2> /dev/null > /dev/null;
		if (($?==10)); then
			PKG_MAX=$PKG_VERSION;
			PKG_LIST="$(echo $PKG_VERSION; echo "$PKG_LIST")";
		else
			PKG_LIST="$(echo "$PKG_LIST"; echo $PKG_VERSION)";
		fi
	done
	echo "$PKG_LIST" | grep -v '^$';
    return 0;
}

function pkginfo {
	if [ -z $1 ]; then
        errcho "pkginfo: missing argument 1 (package name)";
        return 1;
    fi
	PKG_NAME=$1;
	PKG_LIST="$(echo "$(pkgsearch $1; pkginstalled $1)" | uniq)";
	if [[ $(echo "$PKG_LIST" | grep "^${PKG_NAME}$") == "" ]]; then
		errcho "pkginfo: couldn't find exactly match of package $1";
		return 2;
	fi
	PKG_LIST="$(pkgversions $PKG_NAME 2> /dev/null)";
	if (($? != 0)); then
		errcho "Package seems to be not available in package archive (no install canditate)";
	fi
	PKG_DEPS="";
	PKG_CONFL="";
	IFS=$'\n';
	for v in $PKG_LIST; do
		DEPS="$(pkgdeps $PKG_NAME $v | tr -s '[:blank:]' '-' | grep -v '^$')";
		if [[ $DEPS != "" ]]; then
            if [[ $(echo "$DEPS" | grep '^!') != "" ]]; then
                PKG_CONFL="$PKG_CONFL""$v -> ($(echo "$DEPS" | grep '^!' | tr [:space:] ','))$(echo "")";
            fi
            if [[ $(echo "$DEPS" | grep -v '^!') != "" ]]; then
                PKG_DEPS="$PKG_DEPS""$v -> ($(echo "$DEPS" | grep -v '^!' | tr [:space:] ','))$(echo "")";
            fi
        fi
	done
	echo "  --> package found: $PKG_NAME" && \
	echo "         version(s): $(echo "$PKG_LIST" | tr -s '[:space:]' ', ' )" && \
	echo "         archive(s): $(ls /usr/pkg/${PKG_NAME}_*_pkg.tar.gz 2> /dev/null | tr -s [:space:] ', ')" && \
	echo "       dependencies: $(echo "$PKG_DEPS" | grep -v '^$' | sed -e 's|,)$|)|' | tr [:space:] ', ')" && \
	echo "        conflict(s): $(echo "$PKG_CONFL" | grep -v '^$' | sed -e 's|,)$|)|' | tr [:space:] ', ')" && \
	echo "          installed: $(pkginstver $PKG_NAME | tr -s '[:space:]' ', ')";
}

function pkginstver {
	if [ -z $1 ]; then
        errcho "pkginstver: missing argument 1 (package name)";
        return 1;
    fi
	PKG_MAX="";
	PKG_NAME=$1;
	PKG_LIST="";
	for pkg in /usr/pkg/installed.db/${PKG_NAME}_*_pkg.info; do
		if [ ! -r $pkg ]; then continue; fi
		PKG_INFO=$(echo $pkg | sed -e 's|/usr/pkg/installed.db/||') && \
		PKG_ENTRY=$(echo $PKG_INFO | grep -o -e '^.*_.*_pkg.info' | sed -e 's|_pkg.info||') && \
		PKG_VERSION=$(echo $PKG_ENTRY | cut -d'_' -f2-);
		if (($? != 0)); then
			errcho "pkginstver: error while searching for $1";
			return 2;
		fi
		#errcho "Found: $PKG_ENTRY $PKG_VERSION";
		[ -z $PKG_MAX ] && PKG_MAX=$PKG_VERSION;
		if [[ $(echo "$PKG_LIST" | grep "^${PKG_VERSION}$") != "" ]]; then continue; fi
		# remind the maximum version
		versionmatch $PKG_MAX $PKG_VERSION 2> /dev/null > /dev/null;
		if (($?==10)); then
			PKG_MAX=$PKG_VERSION;
			PKG_LIST="$(echo $PKG_VERSION; echo "$PKG_LIST")";
		else
			PKG_LIST="$(echo "$PKG_LIST"; echo $PKG_VERSION)";
		fi
	done
	echo "$PKG_LIST" | grep -v '^$';
    return 0;
}

function pkgdeps {
	if [ -z $1 ]; then
        errcho "pkgdeps: missing argument 1 (package name)";
        return 1;
    fi
	if [ -z $2 ]; then
        errcho "pkgdeps: missing argument 2 (package version)";
        return 2;
    fi
	PKG_LIST=$(pkgsearch $1 $2) || { errcho "pkgdeps: error ($?) while searching for package $1 $2"; return 3; };
	if (($(echo "$PKG_LIST" | wc -l) != 1)); then
		errcho "pkgdeps: couldn't find exactly match of package $1";
		return 6;
	fi
	PKG_NAME=$1;
	PKG_VERSION=$2;
	PKG_ARCHIVE="${PKG_NAME}_${PKG_VERSION}_pkg.tar.gz";
	if [ ! -e /usr/pkg/${PKG_ARCHIVE} ]; then
		errcho "pkgdeps: couldn't find package archive /usr/pkg/$PKG_ARCHIVE";
		return 4;
	fi
	if [ -e /usr/pkg/$PKG_NAME/$PKG_VERSION/deps.pkg ] || [[ $(tar -tzf /usr/pkg/${PKG_ARCHIVE} | grep "^$PKG_VERSION/deps.pkg$") != "" ]]; then
		if [ ! -e /usr/pkg/$PKG_NAME/$PKG_VERSION/deps.pkg ]; then
			mkdir -p /usr/pkg/$PKG_NAME && \
			tar -xzf /usr/pkg/${PKG_ARCHIVE} -C /usr/pkg/$PKG_NAME $PKG_VERSION/deps.pkg || return 5;
		fi
		cat /usr/pkg/$PKG_NAME/$PKG_VERSION/deps.pkg | tr -s '[:blank:]' ':' | tr -s '[:space:]' '\n' | tr ':' ' ' | grep -v '^#' || echo "";
	fi
}

function pkglockedby {
    if [ -z $1 ]; then
        errcho "pkglockedby: missing argument 1 (package name)";
        return 1;
    fi
	if [ -z $2 ]; then
        errcho "pkglockedby: missing argument 2 (package version)";
        return 2;
    fi
    PKG_LIST=$(pkgsearch $1 $2) || { errcho "pkglockedby: error ($?) while searching for package $1 $2"; return 3; };
	if (($(echo "$PKG_LIST" | wc -l) != 1)); then
		errcho "pkglockedby: couldn't find exactly match of package $1";
		return 4;
	fi
    PKG_NAME=$1;
    PKG_VERSION=$2;
    if [ -e /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.lock ]; then
		#echo "/usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.lock found... check if active dependencies exists...";
		PKG_DEPS="$(cat /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.lock | grep -v '^#' | grep -v '^$')";
        #errcho "locked: $PKG_DEPS"
		IFS=$'\n';
		for d in $PKG_DEPS; do
            DEP_NAME=$(echo $d | cut -d' ' -f1) || exit 5;
			INSTVERS="$(pkginstver $DEP_NAME)" || exit 6;
            #errcho "$d --> $INSTVERS";
			if (($(echo $d | wc -w) >= 2)); then
				DEP_VER=$(echo $d | cut -d' ' -f2);
				if [[ $(echo "$INSTVERS" | grep "^$DEP_VER") != "" ]]; then
                    echo $d;
				fi
			elif [[ $INSTVERS != "" ]]; then
				echo $DEP_NAME $(echo "$INSTVERS" | grep -v '^$' | head -1);
			fi
		done
	fi
}

function _pkgremove {

    if [ -z $1 ]; then
        errcho "_pkgremove: missing argument 1 (package name)";
        return 1;
    fi
    PKG_NAME=$1;
	if [ -z $2 ]; then
        errcho "_pkgremove: missing argument 2 (package version)";
        return 2;
    fi
    PKG_VERSION=$2;
	if [ -z $3 ]; then
        PKG_DIFF="";
    else
        # make a difference remove
        PKG_DIFF=$3;
    fi

    if [[ $PKG_DIFF != "" ]] && [ ! -e /usr/pkg/installed.db/${PKG_NAME}_${PKG_DIFF}_pkg.files ]; then
        errcho "_pkgremove: diff file info (/usr/pkg/installed.db/${PKG_NAME}_${PKG_DIFF}_pkg.files) dosn't exists, abort"
        return 3;
    fi

    IFS=$'\n'
	for f in $(tac /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.files); do

        # first check plain line match
        if [[ $PKG_DIFF != "" && \
            $(cat /usr/pkg/installed.db/${PKG_NAME}_${PKG_DIFF}_pkg.files | grep "^$f$") != "" ]]; then
            errcho "_pkgremove: keep line $f, because its part of the new package";
            continue;
        fi
        
        MKDIR=$(echo $f | grep "^mkdir: created directory.*'.*'$" | grep -o "'.*'$" | sed -e "s|^'\(.*\)'$|\1|");
        SYMLINK=$(echo $f | grep "^rm symlink:.*$" | grep -o "'.*' --> '.*'" | sed -e "s|^'\(.*\)' --> '\(.*\)'$|\2 \1|");
        
        if [[ $MKDIR != "" ]]; then
            # ignore
            continue;
        fi
        if [[ $SYMLINK != "" ]]; then
            # recover symbolic links
            LNK_TARGET=$(echo $SYMLINK | cut -d' ' -f2);
            [ ! -z $LNK_TARGET ] || {
                errcho "_pkgremove: link target missing... check /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.files";
                return 8;
            };
            # check link target against diff package
            if [[ $PKG_DIFF != "" && \
                $(cat /usr/pkg/installed.db/${PKG_NAME}_${PKG_DIFF}_pkg.files | grep "^${LNK_TARGET}$") != "" ]]; then
                errcho "_pkgremove: keep $LNK_TARGET, because its part of the new package";
                # keep link information in diff package info
                sed -i -e "1i$f\\" /usr/pkg/installed.db/${PKG_NAME}_${PKG_DIFF}_pkg.files || return 9;
                continue;
            fi
            # recover link
            ln -vfs $SYMLINK >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || return 4;
        elif [[ $(echo $f | grep "^mode of") != "" ]]; then
            # ignore
            continue;
        elif [ -d $f ]; then
            if [[ $(ls -A $f) == "" ]]; then
                saferm $f || return 5;
            else
                echo "Keep $f, is not an empty directory" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
            fi
        elif [ -e $f -o -h $f ]; then
            saferm $f || return 6;
        elif [[ $(echo $f | grep '^/') != "" ]]; then
            echo "already removed: $f" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
        else
            errcho "_pkgremove: unknown: '$f' - abort"
            return 7;
        fi
    done
}

CMD=$(echo $0 | sed -e 's|.sh$||');

if [[ $CMD == *"errcho" ]]; then
	errcho "$@";
elif [[ $CMD == *"pkgsearch" ]]; then
	pkgsearch "$@";
elif [[ $CMD == *"pkgversions" ]]; then
	pkgversions "$@";
elif [[ $CMD == *"pkginfo" ]]; then
	pkginfo "$@";
elif [[ $CMD == *"pkginstalled" ]]; then
	pkginstalled "$@";
elif [[ $CMD == *"pkginstver" ]]; then
	pkginstver "$@";
elif [[ $CMD == *"pkgdeps" ]]; then
	pkgdeps "$@";
elif [[ $CMD == *"pkgdepstree" ]]; then
	pkgdepstree "$@";
elif [[ $CMD == *"pkgmakechain" ]]; then
	pkgmakechain "$@";
elif [[ $CMD == *"versionmatch" ]]; then
	versionmatch "$@";
fi
